home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 January / macpower199701.bin / AMUG / Programming_10 / WASTE 1.3a1.sit / WASTE 1.3a1 Distribution / WASTE 1.3a1 / WEBirthDeath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-23  |  20.1 KB  |  805 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEBirthDeath.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Creation and Destruction, Standard Procs, etc.
  6.  *
  7.  *  Copyright (c) 1993-1996 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. #if GENERATINGCFM
  18. #ifndef __CODEFRAGMENTS__
  19. #include <CodeFragments.h>
  20. #endif
  21. #endif
  22.  
  23. const Point kOneToOneScaling = { 1, 1 };
  24.  
  25. // static variables
  26.  
  27. static WEDrawTextUPP        _weStdDrawTextProc = nil;
  28. static WEPixelToCharUPP        _weStdPixelToCharProc = nil;
  29. static WECharToPixelUPP        _weStdCharToPixelProc = nil;
  30. static WELineBreakUPP        _weStdLineBreakProc = nil;
  31. static WEWordBreakUPP        _weStdWordBreakProc = nil;
  32. static WECharByteUPP        _weStdCharByteProc = nil;
  33. static WECharTypeUPP        _weStdCharTypeProc = nil;
  34. static WEClickLoopUPP        _weStdClickLoopProc = nil;
  35. static WEHiliteDropAreaUPP    _weStdHiliteDropAreaProc = nil;
  36. static WEEraseUPP            _weStdEraseProc = nil;
  37.  
  38. pascal void _WEStdDrawText(Ptr pText, SInt32 textLength, Fixed slop,
  39.                 JustStyleCode styleRunPosition, WEHandle hWE)
  40. {
  41. #pragma unused(hWE)
  42.     DrawJustified(pText, textLength, slop, styleRunPosition,
  43.           kOneToOneScaling, kOneToOneScaling);
  44. }
  45.  
  46. pascal SInt32 _WEStdPixelToChar(Ptr pText, SInt32 textLength, Fixed slop,
  47.                 Fixed *width, WEEdge *edge, JustStyleCode styleRunPosition,
  48.                 Fixed hPos, WEHandle hWE)
  49. {
  50. #pragma unused(hPos, hWE)
  51.     Fixed lastWidth;
  52.     SInt32 offset;
  53.  
  54.     lastWidth = *width;
  55.     offset = PixelToChar(pText, textLength, slop, lastWidth, (Boolean *) edge,
  56.         width, styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  57.  
  58.     // round width to nearest integer value
  59.     // (this is supposed to fix an incompatibility with the WorldScript Power Adapter)
  60.     *width = (*width + 0x00008000) & 0xFFFF0000;
  61.  
  62.     return offset;
  63. }
  64.  
  65. pascal SInt16 _WEStdCharToPixel(Ptr pText, SInt32 textLength, Fixed slop,
  66.                 SInt32 offset, SInt16 direction, JustStyleCode styleRunPosition,
  67.                 SInt16 hPos, WEHandle hWE)
  68. {
  69. #pragma unused(hPos, hWE)
  70.     return CharToPixel(pText, textLength, slop, offset, direction,
  71.             styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  72. }
  73.  
  74. pascal StyledLineBreakCode _WEStdLineBreak(Ptr pText, SInt32 textLength,
  75.                 SInt32 textStart, SInt32 textEnd, Fixed *textWidth,
  76.                 SInt32 *textOffset, WEHandle hWE)
  77. {
  78. #pragma unused(hWE)
  79.     return StyledLineBreak(pText, textLength, textStart, textEnd, 0, textWidth,
  80.                 textOffset);
  81. }
  82.  
  83. pascal void _WEStdWordBreak(Ptr pText, SInt16 textLength, SInt16 offset,
  84.                 WEEdge edge, OffsetTable breakOffsets, ScriptCode script,
  85.                 WEHandle hWE)
  86. {
  87. #pragma unused(hWE)
  88.     FindWordBreaks(pText, textLength, offset, (Boolean) edge, nil, breakOffsets, script);
  89. }
  90.  
  91. pascal SInt16 _WEStdCharByte(Ptr pText, SInt16 textOffset, ScriptCode script,
  92.                 WEHandle hWE)
  93. {
  94. #pragma unused(hWE)
  95.     return CharacterByteType(pText, textOffset, script);
  96. }
  97.  
  98. pascal SInt16 _WEStdCharType(Ptr pText, SInt16 textOffset, ScriptCode script,
  99.                 WEHandle hWE)
  100. {
  101. #pragma unused(hWE)
  102.     return CharacterType(pText, textOffset, script);
  103. }
  104.  
  105. //    _WEScriptToFont, _WEOldWordBreak, _WEOldCharByte and _WEOldCharType
  106. //    are only needed to support version 7.0 / 7.0.1 of MacOS;
  107. //    PowerPC code doesn't need them as PowerPC machines need
  108. //    version 7.1.2 or later anyway.
  109.  
  110. #if ! (SystemSevenFiveOrLater || GENERATINGPOWERPC)
  111.  
  112. pascal SInt16 _WEScriptToFont(ScriptCode script)
  113. {
  114.     // given an explicit script code, return the first font ID in the corresponding range
  115.     // for an explanation of the formula given below, see IM: Text, page B-8
  116.  
  117.     if (script == smRoman)
  118.         return 2;
  119.     else if ((script > smRoman) && (script <= smUninterp))
  120.         return (0x3E00 + 0x200 * script);
  121.     else
  122.         return systemFont;    // unknown script code (?)
  123. }
  124.  
  125. pascal void _WEOldWordBreak(Ptr pText, SInt16 textLength, SInt16 offset,
  126.                 WEEdge edge, OffsetTable breakOffsets, ScriptCode script,
  127.                 WEHandle hWE)
  128. {
  129.     GrafPtr savePort, tempPort;
  130.     SInt16 saveFont;
  131.  
  132.     // the old (now obsolete) FindWord routine gets an implicit script parameter through
  133.     // the current graphics port txFont field, so first of all we must have a valid port
  134.     GetPort(&savePort);
  135.     tempPort = (*hWE)->port;
  136.     SetPort(tempPort);
  137.  
  138.     // then set the txFont field to a font number in the specified script range
  139.     saveFont = tempPort->txFont;
  140.     TextFont(_WEScriptToFont(script));
  141.  
  142.     // call _FindWord
  143.     FindWord(pText, textLength, offset, (Boolean)edge, nil, breakOffsets);
  144.  
  145.     // restore font and port
  146.     TextFont(saveFont);
  147.     SetPort(savePort);
  148.  
  149. }
  150.  
  151. pascal SInt16 _WEOldCharByte(Ptr pText, SInt16 textOffset, ScriptCode script,
  152.                 WEHandle hWE)
  153. {
  154.     GrafPtr savePort, tempPort;
  155.     SInt16 saveFont;
  156.     SInt16 retVal;
  157.  
  158.     // the old (now obsolete) CharByte routine gets an implicit script parameter through
  159.     // the current graphics port txFont field, so first of all we must have a valid port
  160.     GetPort(&savePort);
  161.     tempPort = (*hWE)->port;
  162.     SetPort(tempPort);
  163.  
  164.     // then set the txFont field to a font number in the specified script range
  165.     saveFont = tempPort->txFont;
  166.     TextFont(_WEScriptToFont(script));
  167.  
  168.     // call _CharByte
  169.     retVal = CharByte(pText, textOffset);
  170.  
  171.     // restore font and port
  172.     TextFont(saveFont);
  173.     SetPort(savePort);
  174.  
  175.     return retVal;
  176. }
  177.  
  178. pascal SInt16 _WEOldCharType(Ptr pText, SInt16 textOffset, ScriptCode script,
  179.                 WEHandle hWE)
  180. {
  181.     GrafPtr savePort, tempPort;
  182.     SInt16 saveFont;
  183.     SInt16 retVal;
  184.  
  185.     // the old (now obsolete) CharType routine gets an implicit script parameter through
  186.     // the current graphics port txFont field, so first of all we must have a valid port
  187.     GetPort(&savePort);
  188.     tempPort = (*hWE)->port;
  189.     SetPort(tempPort);
  190.  
  191.     // then set the txFont field to a font number in the specified script range
  192.     saveFont = tempPort->txFont;
  193.     TextFont(_WEScriptToFont(script));
  194.  
  195.     // call _CharType
  196.     retVal = CharType(pText, textOffset);
  197.  
  198.     // restore font and port
  199.     TextFont(saveFont);
  200.     SetPort(savePort);
  201.  
  202.     return retVal;
  203.  
  204. }
  205.  
  206. #endif
  207.  
  208. pascal Boolean _WEStdClickLoop(WEHandle hWE)
  209. {
  210.     WEPtr pWE = *hWE;        // assume WE record is already locked
  211.     Point mouseLoc;
  212.     SInt32 currentOffset;
  213.     SInt32 maxOffset;
  214.     SInt32 vDelta = 0;
  215.     SInt32 hDelta = 0;
  216.  
  217.     // do nothing if auto-scroll is disabled or if we're inactive
  218.     if (!BTST(pWE->features, weFAutoScroll) || !BTST(pWE->flags, weFActive))
  219.         return true;
  220.  
  221.     // get current mouse location, in local coords
  222.     // we can safely assume the graphics port is set up correctly
  223.     GetMouse(&mouseLoc);
  224.  
  225.     // HANDLE VERTICAL AUTOSCROLL
  226.     currentOffset = pWE->viewRect.top - pWE->destRect.top;
  227.     maxOffset = (pWE->destRect.bottom - pWE->destRect.top) - (pWE->viewRect.bottom - pWE->viewRect.top);
  228.  
  229.     // is the mouse below the view rect?
  230.     if (mouseLoc.v > pWE->viewRect.bottom)
  231.     {
  232.         // is there anything hidden below the view rect?
  233.         if (currentOffset < maxOffset)
  234.         {
  235.             // then scroll down: calculate the scroll delta
  236.             vDelta = pWE->viewRect.bottom - mouseLoc.v;
  237.  
  238.             // pin the new vertical offset to the bottom of the dest rectangle
  239.             if (vDelta < (currentOffset - maxOffset))
  240.                 vDelta = currentOffset - maxOffset;
  241.  
  242.             // never scroll by more than kMaxScrollDelta pixels
  243.             if (vDelta < -kMaxScrollDelta)
  244.                 vDelta = -kMaxScrollDelta;
  245.         }
  246.     }
  247.  
  248.     // is the mouse above the view rect?
  249.     else if (mouseLoc.v < pWE->viewRect.top)
  250.     {
  251.         // is there anything hidden above the view rect?
  252.         if (currentOffset > 0)
  253.         {
  254.             // then scroll up: calculate the scroll delta
  255.             vDelta = pWE->viewRect.top - mouseLoc.v;
  256.  
  257.             // pin the new vertical offset to the top of the dest rectangle
  258.             if (vDelta > currentOffset)
  259.                 vDelta = currentOffset;
  260.  
  261.             // never scroll by more than kMaxScrollDelta pixels
  262.             if (vDelta > kMaxScrollDelta)
  263.                 vDelta = kMaxScrollDelta;
  264.         }
  265.     }
  266.  
  267.     // HANDLE HORIZONTAL AUTOSCROLL
  268.     currentOffset = pWE->viewRect.left - pWE->destRect.left;
  269.     maxOffset = (pWE->destRect.right - pWE->destRect.left) - (pWE->viewRect.right - pWE->viewRect.left);
  270.  
  271.     // is the mouse to the right of the view rect?
  272.     if (mouseLoc.h > pWE->viewRect.right)
  273.     {
  274.         // is there anything hidden to the right of the view rect?
  275.         if (currentOffset < maxOffset)
  276.         {
  277.             // then scroll right: calculate the scroll delta
  278.             hDelta = pWE->viewRect.right - mouseLoc.h;
  279.  
  280.             // pin the new vertical offset to the rightmost edge
  281.             // of the dest rectangle
  282.             if (hDelta < (currentOffset - maxOffset))
  283.                 hDelta = currentOffset - maxOffset;
  284.  
  285.             // never scroll by more than kMaxScrollDelta pixels
  286.             if (hDelta < -kMaxScrollDelta)
  287.                 hDelta = -kMaxScrollDelta;
  288.         }
  289.     }
  290.  
  291.     // is the mouse to the left of the view rect?
  292.     else if (mouseLoc.h < pWE->viewRect.left)
  293.     {
  294.         // is there anything hidden to the left of the view rect?
  295.         if (currentOffset > 0)
  296.         {
  297.             // then scroll up: calculate the scroll delta
  298.             hDelta = pWE->viewRect.left - mouseLoc.h;
  299.  
  300.             // pin the new horizontal offset to the leftmost edge
  301.             // of the dest rectangle
  302.             if (hDelta > currentOffset)
  303.                 hDelta = currentOffset;
  304.  
  305.             // never scroll by more than kMaxScrollDelta pixels
  306.             if (hDelta > kMaxScrollDelta)
  307.                 hDelta = kMaxScrollDelta;
  308.         }
  309.     }
  310.  
  311.     if ((vDelta != 0) || (hDelta != 0))
  312.     {
  313.         // do the scroll
  314.         WEScroll(hDelta, vDelta, hWE);
  315.  
  316.         // notify our client we have scrolled the text
  317.         if (pWE->scrollProc != nil)
  318.         {
  319.             CallWEScrollProc(hWE, pWE->scrollProc);
  320.         }
  321.     }
  322.  
  323.     return true;
  324. }
  325.  
  326. pascal OSErr _WEStdHiliteDropArea(DragReference drag, Boolean hiliteFlag, WEHandle hWE)
  327. {
  328.     WEPtr pWE = *hWE;        // assume WE record is already locked
  329.     RgnHandle tmpRgn;
  330.     OSErr err;
  331.  
  332.     if (hiliteFlag)
  333.     {
  334.         tmpRgn = NewRgn();
  335.         CopyRgn(pWE->viewRgn, tmpRgn);
  336.         InsetRgn(tmpRgn, -kTextMargin, -kTextMargin);
  337.         err = ShowDragHilite(drag, tmpRgn, true);
  338.         DisposeRgn(tmpRgn);
  339.     }
  340.     else
  341.     {
  342.         err = HideDragHilite(drag);
  343.     }
  344.     return err;
  345. }
  346.  
  347. pascal void _WEStdErase(const Rect *area, WEHandle hWE)
  348. {
  349. #pragma unused(hWE)
  350.     EraseRect(area);
  351. }
  352.  
  353. pascal OSErr _WERegisterWithTSM(WEHandle hWE)
  354. {
  355.     WEPtr pWE = *hWE;    // assume WE record is already locked
  356.     InterfaceTypeList typeList;
  357.     OSErr err;
  358.  
  359.     // do nothing if the Text Services Manager isn't available
  360.     if (BTST(pWE->flags, weFHasTextServices))
  361.     {
  362.         typeList[0] = kTextService;
  363.         if ((err = NewTSMDocument(1, typeList, &pWE->tsmReference, (SInt32) hWE)) != noErr)
  364.         {
  365.             // we don't consider it an error if our client application isn't TSM-aware
  366.             if (err != tsmNeverRegisteredErr)
  367.             {
  368.                 goto cleanup;
  369.             }
  370.         }
  371.     }
  372.  
  373.     // clear result code
  374.     err = noErr;
  375.  
  376. cleanup:
  377.     // return result code
  378.     return err;
  379. }
  380.  
  381. pascal void _WESetStandardHooks(WEHandle hWE)
  382. {
  383.     WEPtr pWE;
  384.  
  385.     // the first time we're called, create routine descriptors
  386.     if (_weStdDrawTextProc == nil)
  387.     {
  388.         _weStdDrawTextProc = NewWEDrawTextProc(_WEStdDrawText);
  389.         _weStdPixelToCharProc = NewWEPixelToCharProc(_WEStdPixelToChar);
  390.         _weStdCharToPixelProc = NewWECharToPixelProc(_WEStdCharToPixel);
  391.         _weStdLineBreakProc = NewWELineBreakProc(_WEStdLineBreak);
  392.  
  393. #if ! (SystemSevenFiveOrLater || GENERATINGPOWERPC)
  394.  
  395.         if (GetScriptManagerVariable(smVersion) < 0x0710)
  396.         {
  397.             // pre-7.1 version of the Script Manager: must use old hooks
  398.             _weStdWordBreakProc = NewWEWordBreakProc(_WEOldWordBreak);
  399.             _weStdCharByteProc = NewWECharByteProc(_WEOldCharByte);
  400.             _weStdCharTypeProc = NewWECharTypeProc(_WEOldCharType);
  401.         }
  402.         else
  403. #endif
  404.         {
  405.             // Script Manager version 7.1 or newer
  406.             _weStdWordBreakProc = NewWEWordBreakProc(_WEStdWordBreak);
  407.             _weStdCharByteProc = NewWECharByteProc(_WEStdCharByte);
  408.             _weStdCharTypeProc = NewWECharTypeProc(_WEStdCharType);
  409.         }
  410.  
  411.         _weStdClickLoopProc = NewWEClickLoopProc(_WEStdClickLoop);
  412.         _weStdHiliteDropAreaProc = NewWEHiliteDropAreaProc(_WEStdHiliteDropArea);
  413.         _weStdEraseProc = NewWEEraseProc(_WEStdErase);
  414.  
  415.     } // if called for the first time
  416.  
  417.     // replace null hook fields with the addresses of the standard hooks
  418.  
  419.     pWE = *hWE;
  420.  
  421.     if (pWE->drawTextHook == nil)
  422.     {
  423.         pWE->drawTextHook = _weStdDrawTextProc;
  424.     }
  425.     if (pWE->pixelToCharHook == nil)
  426.     {
  427.         pWE->pixelToCharHook = _weStdPixelToCharProc;
  428.     }
  429.     if (pWE->charToPixelHook == nil)
  430.     {
  431.         pWE->charToPixelHook = _weStdCharToPixelProc;
  432.     }
  433.     if (pWE->lineBreakHook == nil)
  434.     {
  435.         pWE->lineBreakHook = _weStdLineBreakProc;
  436.     }
  437.     if (pWE->wordBreakHook == nil)
  438.     {
  439.         pWE->wordBreakHook = _weStdWordBreakProc;
  440.     }
  441.     if (pWE->charByteHook == nil)
  442.     {
  443.         pWE->charByteHook = _weStdCharByteProc;
  444.     }
  445.     if (pWE->charTypeHook == nil)
  446.     {
  447.         pWE->charTypeHook = _weStdCharTypeProc;
  448.     }
  449.     if (pWE->clickLoop == nil)
  450.     {
  451.         pWE->clickLoop = _weStdClickLoopProc;
  452.     }
  453.     if (pWE->hiliteDropAreaHook == nil)
  454.     {
  455.         pWE->hiliteDropAreaHook = _weStdHiliteDropAreaProc;
  456.     }
  457.     if (pWE->eraseHook == nil)
  458.     {
  459.         pWE->eraseHook = _weStdEraseProc;
  460.     }
  461. }
  462.  
  463. pascal OSErr WENew(const LongRect *destRect, const LongRect *viewRect, UInt32 features, WEHandle *hWE)
  464. {
  465.     WEPtr pWE = nil;
  466.     UInt32 allocFlags = kAllocClear;
  467.     SInt32 response;
  468.     Rect r;
  469.     OSErr err;
  470.  
  471.     // allocate the WE record
  472.     if ((err = _WEAllocate(sizeof(WERec), allocFlags, (Handle *)hWE)) != noErr)
  473.     {
  474.         goto cleanup;
  475.     }
  476.  
  477.     // lock it down
  478.     HLock((Handle)*hWE);
  479.     pWE = **hWE;
  480.  
  481.     // get active port
  482.     GetPort(&pWE->port);
  483.  
  484.     // determine whether temporary memory should be used for data structures
  485.     if (BTST(features, weFUseTempMem))
  486.     {
  487.         allocFlags += kAllocTemp;
  488.     }
  489.  
  490.     // allocate the text handle (initially empty)
  491.     if ((err = _WEAllocate(0, allocFlags, (Handle *)&pWE->hText)) != noErr)
  492.     {
  493.         goto cleanup;
  494.     }
  495.  
  496.     // allocate the line array
  497.     if ((err = _WEAllocate(2 * sizeof(LineRec), allocFlags, (Handle *)&pWE->hLines)) != noErr)
  498.     {
  499.         goto cleanup;
  500.     }
  501.  
  502.     // allocate the style table
  503.     if ((err = _WEAllocate(sizeof(StyleTableElement), allocFlags, (Handle *)&pWE->hStyles)) != noErr)
  504.     {
  505.         goto cleanup;
  506.     }
  507.  
  508.     // allocate the run array
  509.     if ((err = _WEAllocate(2 * sizeof(RunArrayElement), allocFlags, (Handle *)&pWE->hRuns)) != noErr)
  510.     {
  511.         goto cleanup;
  512.     }
  513.  
  514.     // allocate the user info array
  515.     if ((err = _WEAllocate(sizeof(WEUserInfoEntry), allocFlags, &pWE->hUserInfo)) != noErr)
  516.     {
  517.         goto cleanup;
  518.     }
  519.  
  520.     // check for the presence of various system software features
  521.     // determine whether Color Quickdraw is available
  522.     if ((Gestalt(gestaltQuickdrawVersion, &response) == noErr) && (response >= gestalt8BitQD))
  523.     {
  524.         BSET(pWE->flags, weFHasColorQD);
  525.     }
  526.  
  527.     // determine whether the Drag Manager is available
  528.     if ((Gestalt(gestaltDragMgrAttr, &response) == noErr) && BTST(response, gestaltDragMgrPresent))
  529.     {
  530. #if GENERATINGCFM
  531.         if ((UInt32) NewDrag != kUnresolvedCFragSymbolAddress)
  532. #endif
  533.             BSET(pWE->flags, weFHasDragManager);
  534.  
  535. #if WASTE_TRANSLUCENT_DRAGS
  536.         // determine whether translucent drags are available
  537.         if (BTST(response, 3))
  538.         {
  539. #if GENERATINGCFM
  540.             if ((UInt32) SetDragImage != kUnresolvedCFragSymbolAddress)
  541. #endif
  542.                 BSET(pWE->flags, weFHasTranslucentDrags);
  543.         }
  544. #endif
  545.     }
  546.  
  547.     // determine whether the Text Services manager is available
  548.     if (Gestalt(gestaltTSMgrVersion, &response) == noErr)
  549.     {
  550.         BSET(pWE->flags, weFHasTextServices);
  551.     }
  552.  
  553.     // determine if there are any non-Roman scripts enabled
  554.     if (GetScriptManagerVariable(smEnabled) > 1)
  555.     {
  556.         BSET(pWE->flags, weFNonRoman);
  557.  
  558.         // determine whether a double-byte script is installed
  559.         if (GetScriptManagerVariable(smDoubleByte) != 0)
  560.         {
  561. #if GENERATING68K
  562.             BSET(pWE->flags, weFDoubleByte);    // the WorldScript Power Adapter breaks this :-(
  563. #else
  564.             ScriptCode script;
  565.             for ( script = smRoman; script <= smKlingon; script++ )
  566.             {
  567.                 if (GetScriptVariable(script, smEnabled) &&
  568.                 ! BTST(GetScriptVariable(script, smScriptFlags), smsfSingByte))
  569.                 {
  570.                     BSET(pWE->flags, weFDoubleByte);
  571.                     break;
  572.                 }
  573.             }
  574. #endif
  575.         }
  576.  
  577.         // determine whether a bidirectional script is installed
  578.         if (GetScriptManagerVariable(smBidirect) != 0)
  579.         {
  580.             BSET(pWE->flags, weFBidirectional);
  581.         }
  582.     }
  583.  
  584.     // initialize miscellaneous fields of the WE record
  585.     pWE->nLines = 1;
  586.     pWE->nStyles = 1;
  587.     pWE->nRuns = 1;
  588.     pWE->viewRect = *viewRect;
  589.     pWE->destRect = *destRect;
  590.     pWE->direction = weDirDefault;
  591.     pWE->features = features;
  592.     pWE->tsmAreaStart = kInvalidOffset;
  593.     pWE->tsmAreaEnd = kInvalidOffset;
  594.     pWE->dragCaretOffset = kInvalidOffset;
  595.  
  596.     // initialize hook fields with the addresses of the standard hooks
  597.     _WESetStandardHooks(*hWE);
  598.  
  599.     // create a region to hold the view rectangle
  600.     pWE->viewRgn = NewRgn();
  601.     WELongRectToRect(viewRect, &r);
  602.     RectRgn(pWE->viewRgn, &r);
  603.  
  604.     // initialize the style run array
  605.     (*pWE->hRuns)[1].runStart = 1;
  606.     (*pWE->hRuns)[1].styleIndex = -1;
  607.  
  608.     // initialize the style table
  609.     (*pWE->hStyles)[0].refCount = 1;
  610.  
  611.     // copy text attributes from the active graphics port
  612.     (*pWE->hStyles)[0].info.runStyle.tsFont = pWE->port->txFont;
  613.     (*pWE->hStyles)[0].info.runStyle.tsSize = pWE->port->txSize;
  614.     (*pWE->hStyles)[0].info.runStyle.tsFace = pWE->port->txFace;
  615.     if (BTST(pWE->flags, weFHasColorQD))
  616.     {
  617.         GetForeColor(&(*pWE->hStyles)[0].info.runStyle.tsColor);
  618.     }
  619.     _WEFillFontInfo(pWE->port, &(*pWE->hStyles)[0].info);
  620.  
  621.     // initialize the line array
  622.     if ((err = WECalText(*hWE)) != noErr)
  623.     {
  624.         goto cleanup;
  625.     }
  626.  
  627.     // register with the Text Services Manager
  628.     if ((err = _WERegisterWithTSM(*hWE)) != noErr)
  629.     {
  630.         goto cleanup;
  631.     }
  632.  
  633.     // unlock the WE record
  634.     HUnlock((Handle)*hWE);
  635.  
  636.     // skip clean-up section
  637.     return noErr;
  638.  
  639. cleanup:
  640.     // clean up
  641.     if (pWE != nil)
  642.     {
  643.         _WEForgetHandle((Handle *) &pWE->hText);
  644.         _WEForgetHandle((Handle *) &pWE->hLines);
  645.         _WEForgetHandle((Handle *) &pWE->hStyles);
  646.         _WEForgetHandle((Handle *) &pWE->hRuns);
  647.         _WEForgetHandle(&pWE->hUserInfo);
  648.         if (pWE->viewRgn != nil)
  649.         {
  650.             DisposeRgn(pWE->viewRgn);
  651.         }
  652.     }
  653.     _WEForgetHandle((Handle *)hWE);
  654.  
  655.     return err;
  656. }
  657.  
  658. pascal void _WEResetStyleTable(WEHandle hWE)
  659. {
  660.     WEPtr pWE = *hWE;    // assume WE record is already locked
  661.     SInt32 index;
  662.     StyleTableElement *pTable;
  663.     Boolean saveTableLock;
  664.  
  665.     // sanity check
  666.     if (pWE->hStyles == nil)
  667.         return;
  668.  
  669.     // lock the style table
  670.     saveTableLock = _WESetHandleLock((Handle) pWE->hStyles, true);
  671.     pTable = *pWE->hStyles;
  672.  
  673.     // walk the style table, disposing of all embedded objects referenced there
  674.     index = pWE->nStyles;
  675.     while ( --index >= 0 )
  676.     {
  677.  
  678. #if WASTE_OBJECTS
  679.         if ((pTable->refCount > 0) && (pTable->info.runStyle.tsObject != nil))
  680.         {
  681.             _WEFreeObject(pTable->info.runStyle.tsObject);
  682.         }
  683. #endif
  684.  
  685.         pTable->refCount = 0;
  686.         pTable++;
  687.     };
  688.  
  689.     // unlock the style table
  690.     _WESetHandleLock((Handle) pWE->hStyles, saveTableLock);
  691. }
  692.  
  693. pascal void WEDispose(WEHandle hWE)
  694. {
  695.     WEPtr pWE;
  696.  
  697.     // sanity check: make sure WE isn't nil
  698.     if (hWE == nil)
  699.     {
  700.         return;
  701.     }
  702.  
  703.     // lock the WE record
  704.     HLock((Handle) hWE);
  705.     pWE = *hWE;
  706.  
  707.     // clear the Undo buffer
  708.     _WEForgetAction(&pWE->hActionStack);
  709.  
  710.     // unregister with the Text Services Manager
  711.     if (pWE->tsmReference != nil)
  712.     {
  713.         DeleteTSMDocument(pWE->tsmReference);
  714.         pWE->tsmReference = nil;
  715.     }
  716.  
  717.     // dispose of the offscreen graphics world
  718.     if (pWE->offscreenPort != nil)
  719.     {
  720.         DisposeGWorld((GWorldPtr)pWE->offscreenPort);
  721.         pWE->offscreenPort = nil;
  722.     }
  723.  
  724. #if WASTE_OBJECTS
  725.     // release all embedded objects we know about
  726.     _WEResetStyleTable(hWE);
  727.  
  728.     // dispose instance-specific object handler table
  729.     _WEForgetHandle((Handle *) &pWE->hObjectHandlerTable);
  730. #endif
  731.  
  732.     // dispose of auxiliary data structures
  733.     _WEForgetHandle((Handle *) &pWE->hText);
  734.     _WEForgetHandle((Handle *) &pWE->hLines);
  735.     _WEForgetHandle((Handle *) &pWE->hStyles);
  736.     _WEForgetHandle((Handle *) &pWE->hRuns);
  737.     _WEForgetHandle(&pWE->hUserInfo);
  738.     DisposeRgn(pWE->viewRgn);
  739.  
  740.     // dispose of the WE record
  741.     DisposeHandle((Handle) hWE);
  742. }
  743.  
  744. pascal OSErr WEUseText(Handle text, WEHandle hWE)
  745. {
  746.     WEPtr pWE;
  747.     RunArrayPtr pRuns;
  748.     LinePtr pLines;
  749.     SInt32 textLength;
  750.     Boolean saveWELock;
  751.  
  752.     // lock the WE record
  753.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  754.     pWE = *hWE;
  755.  
  756.     // stop any ongoing inline session
  757.     WEStopInlineSession(hWE);
  758.  
  759.     // reset modification count and clear undo buffer, if any
  760.     WEResetModCount(hWE);
  761.  
  762.     // reset the style table, disposing of all embedded objects it references
  763.     _WEResetStyleTable(hWE);
  764.  
  765.     // install the text
  766.     _WEForgetHandle(&pWE->hText);
  767.     pWE->hText = text;
  768.     textLength = GetHandleSize(text);
  769.     pWE->textLength = textLength;
  770.  
  771.     // reset the run array
  772.     SetHandleSize((Handle) pWE->hRuns, 2 * sizeof(RunArrayElement));
  773.     pWE->nRuns = 1;
  774.     pRuns = *pWE->hRuns;
  775.     pRuns[1].runStart = textLength + 1;
  776.     pRuns[1].styleIndex = -1;
  777.  
  778.     // fix the refCount of the style table entry referenced by the only run
  779.     (*pWE->hStyles)[pRuns[0].styleIndex].refCount = 1;
  780.  
  781.     // reset the line array
  782.     SetHandleSize((Handle) pWE->hLines, 2 * sizeof(LineRec));
  783.     pWE->nLines = 1;
  784.     pLines = *pWE->hLines;
  785.     _WEBlockClr(pLines, 2 * sizeof(LineRec));
  786.     pLines[1].lineStart = textLength;
  787.  
  788.     // reset several fields of the WE record
  789.     pWE->selStart = 0;
  790.     pWE->selEnd = 0;
  791.     pWE->firstByte = 0;
  792.     pWE->clickCount = 0;
  793.     pWE->tsmAreaStart = kInvalidOffset;
  794.     pWE->tsmAreaEnd = kInvalidOffset;
  795.     pWE->dragCaretOffset = kInvalidOffset;
  796.  
  797.     // recalculate and redraw everything
  798.     // err = _WERedraw(0, LONG_MAX, hWE);
  799.  
  800.     // unlock the WE record
  801.     _WESetHandleLock((Handle) hWE, saveWELock);
  802.  
  803.     return noErr;
  804. }
  805.